package com.circus.trace.controller.product;

import java.util.List;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.lang.ContinueLoop;
import org.nutz.lang.Each;
import org.nutz.lang.ExitLoop;
import org.nutz.lang.Lang;
import org.nutz.lang.LoopException;
import org.nutz.lang.util.NutMap;
import org.nutz.plugin.spring.boot.service.entity.PageredData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.circus.trace.bean.material.Coffee;
import com.circus.trace.bean.material.area.Manor;
import com.circus.trace.bean.product.Product;
import com.circus.trace.bean.product.Product.PackageType;
import com.circus.trace.bean.product.ProductCoffee;
import com.circus.trace.biz.material.CoffeeService;
import com.circus.trace.biz.material.area.AreaService;
import com.circus.trace.biz.material.area.ManorService;
import com.circus.trace.biz.material.area.StorageService;
import com.circus.trace.biz.material.transport.TransportService;
import com.circus.trace.biz.product.ProductCoffeeService;
import com.circus.trace.biz.product.ProductService;
import com.circus.trace.controller.BaseController;
import com.circus.trace.ext.shiro.anno.SINORequiresPermissions;
import com.circus.trace.vo.InstallPermission;
import com.google.common.collect.Lists;

import club.zhcs.common.Result;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@RestController
@RequestMapping("product")
public class ProductController extends BaseController {

    @Autowired
    ProductService productService;
    @Autowired
    CoffeeService coffeeService;

    @Autowired
    StorageService storageService;

    @Autowired
    ManorService manorService;

    @Autowired
    TransportService transportService;

    @Autowired
    AreaService areaService;
    @Autowired
    ProductCoffeeService productCoffeeService;

    public static class ProductDTO extends Product {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        private List<Long> materialIds;

        public List<Long> getMaterialIds() {
            return materialIds;
        }

        public void setMaterialIds(List<Long> materialIds) {
            this.materialIds = materialIds;
        }

    }

    @GetMapping("infos")
    public Result infos() {
        List<NutMap> types = Lists.newArrayList();
        Lang.each(Product.PackageType.values(), new Each<PackageType>() {

            @Override
            public void invoke(int index, PackageType type, int length) throws ExitLoop, ContinueLoop, LoopException {
                types.add(Lang.obj2nutmap(type).addv("orgin", type.name()));
            }
        });
        return Result.success().addData("types", types).addData("materials", coffeeService.query(Cnd.where("enabled", "=", true)));
    }

    @GetMapping("list")
    @SINORequiresPermissions(InstallPermission.PRODUCT_LIST)
    @ApiOperation(value = "产品分页列表")
    public Result list(@RequestParam(value = "page", defaultValue = "1") @ApiParam("页码") int page) {
        PageredData<Product> pager = productService.searchByPage(fixPage(page), Cnd.where("enabled", "=", true).desc("id"));
        Lang.each(pager.getDataList(), new Each<Product>() {

            @Override
            public void invoke(int index, Product product, int length) throws ExitLoop, ContinueLoop, LoopException {
                ProductDTO dto = Lang.map2Object(Lang.obj2nutmap(product), ProductDTO.class);
                dto.setMaterialIds(productCoffeeService.coffeeIds(product.getId()));
                pager.getDataList().set(index, dto);
            }
        });
        return Result.success().addData("pager", pager);
    }

    @GetMapping("search")
    @SINORequiresPermissions(InstallPermission.PRODUCT_LIST)
    @ApiOperation(value = "产品分页检索")
    public Result search(@RequestParam("key") @ApiParam("搜索关键字") String key,
                         @RequestParam(value = "page", defaultValue = "1") @ApiParam("页码") int page) {
        PageredData<Product> pager = productService.searchByKeyAndPage(
                                                                       fixSearchKey(key),
                                                                       fixPage(page),
                                                                       Cnd.where("enabled", "=", true),
                                                                       "name",
                                                                       "productiveTime",
                                                                       "productiveAddress",
                                                                       "manufacturer")
                                                   .addParam("key", key);
        Lang.each(pager.getDataList(), new Each<Product>() {

            @Override
            public void invoke(int index, Product product, int length) throws ExitLoop, ContinueLoop, LoopException {
                ProductDTO dto = Lang.map2Object(Lang.obj2nutmap(product), ProductDTO.class);
                dto.setMaterialIds(productCoffeeService.coffeeIds(product.getId()));
                pager.getDataList().set(index, dto);
            }
        });
        return Result.success()
                     .addData("pager", pager);
    }

    @GetMapping("detail")
    public Result detail(@RequestParam("id") long id) {
        Product product = productService.fetch(id);
        if (product != null) {
            List<Coffee> coffees = coffeeService.query(Cnd.where("id", "in", productCoffeeService.coffeeIds(id)));
            Lang.each(coffees, new Each<Coffee>() {

                @Override
                public void invoke(int index, Coffee coffee, int length) throws ExitLoop, ContinueLoop, LoopException {
                    coffee.setStorage(storageService.fetch(coffee.getStorageId()));
                    coffee.setTransport(transportService.fetch(coffee.getTransportId()));
                    Manor manor = manorService.fetch(coffee.getManorId());
                    if (manor != null) {
                        manor.setArea(areaService.fetch(manor.getAreaId()));
                    }
                    coffee.setManor(manor);
                }
            });
            product.setCoffees(coffees);
        }
        return Result.success().addData("product", product);
    }

    @PostMapping(value = "add")
    @SINORequiresPermissions(InstallPermission.PRODUCT_ADD)
    @ApiOperation(value = "新增产品")
    public Result save(@RequestBody ProductDTO product) {
        if (productService.save(product) == null) {
            return Result.fail("保存产品信息失败!");
        } else {
            Lang.each(product.getMaterialIds(), new Each<Long>() {

                @Override
                public void invoke(int index, Long ele, int length) throws ExitLoop, ContinueLoop, LoopException {
                    ProductCoffee pc = new ProductCoffee();
                    pc.setProductId(product.getId());
                    pc.setCoffeeId(ele);
                    productCoffeeService.save(pc);
                }
            });
        }
        return Result.success().addData("product", product);
    }

    @PostMapping(value = "edit")
    @SINORequiresPermissions(InstallPermission.PRODUCT_EDIT)
    public Result edit(@RequestBody ProductDTO product) {
        if (productService.update(product) != 1) {
            return Result.fail("更新产品信息失败!");
        } else {
            productCoffeeService.clear(Cnd.where("productId", "=", product.getId()));
            Lang.each(product.getMaterialIds(), new Each<Long>() {

                @Override
                public void invoke(int index, Long ele, int length) throws ExitLoop, ContinueLoop, LoopException {
                    ProductCoffee pc = new ProductCoffee();
                    pc.setProductId(product.getId());
                    pc.setCoffeeId(ele);
                    productCoffeeService.save(pc);
                }
            });
        }
        return Result.success();
    }

    /**
     * 删除产品
     * 
     * @param id
     *            产品id
     * @return
     */
    @GetMapping("delete/{id}")
    @SINORequiresPermissions(value = {InstallPermission.AREA_DELETE})
    @ApiOperation("删除产品")
    public Result delete(@PathVariable("id") @ApiParam("产品id") long id) {
        return productService.update(Chain.make("enabled", false), Cnd.where("id", "=", id)) == 1 ? Result.success()
                                                                                                  : Result.fail("删除产品失败!");
    }

}
